﻿using Castle.Core.Logging;
using DotNetOpenAuth.OAuth2;
using Inovout.Cloud.Applications.Models;
using Inovout.Cloud.Applications.Security;
using Inovout.Cloud.Applications.Security.Models;
using Inovout.Cloud.Applications.Security.Services;
using Inovout.Cloud.Applications.Services;
using Inovout.Cloud.Models;
using Inovout.Cloud.Services;
using Inovout.Memberships;
using Inovout.Memberships.Services;
using Inovout.Security;
using Inovout.Services;
using Inovout.Web.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;

namespace Inovout.Cloud.Web.Http
{
    //[EnableCors("*", "*", "*")]
    public class CloudHttpController : BaseHttpController
    {
        protected IExtendedLogger Logger { get;  set; }
        protected IProjectService projectService;
        public CloudHttpController()
        {
            Logger = Inovout.ComponentRegistry.Resolve<IExtendedLogger>();
            this.projectService = ComponentRegistry.Resolve<ProjectService>();
        }
        protected ApplicationUserPrincipal ApplicationUserPrincipal
        {
            get { return Thread.CurrentPrincipal as ApplicationUserPrincipal; }
        }
        protected IApplicationUser ApplicationUser
        {
            get { return ApplicationUserPrincipal.ApplicationUser; }
        }
        private IMembershipUser _membershipUser;
        protected IMembershipUser MembershipUser
        {
            get { return _membershipUser??ApplicationUserPrincipal.MembershipUser; }
        }

        protected IMembership Membership
        {
            get { return MembershipUser.Membership; }
        }
        protected ISystemUser SystemUser
        {
            get { return MembershipUser.SystemUser; }
        }
        protected Project Project { get; set; }
        protected override void Initialize()
        {
            object projectName = null;
            if (base.TryGetParameterValue("project", out projectName))
            {
                Project = projectService.FindByName(projectName.ToString());
                if (Project == null)
                {
                    throw new System.Exception(string.Format("{0}项目不存在", projectName));
                }
            }
        }
        private bool AuthorizeAccessControl(out IApplicationUser applicationUser, out IMembershipUser membershipUser)
        {
            object membershipIdentifier = null;
            object applicationIdentifier = null;
            if (base.TryGetParameterValue("x-membership-identifier", out membershipIdentifier) &&
                base.TryGetParameterValue("x-application-identifier", out membershipIdentifier))
            {
                applicationUser = ComponentRegistry.Resolve<ApplicationUserService>().FindByName(applicationIdentifier.ToString());
                ApplicationIdentifier = applicationIdentifier as string;

                membershipUser = ComponentRegistry.Resolve<IMembershipUserService>().FindByClaimedIdentifier(membershipIdentifier.ToString());

                return true;
            }
            applicationUser = null;
            membershipUser = null;
            return false;
        }

        private bool AuthorizeOAuth(out IApplicationUser applicationUser, out IMembershipUser membershipUser)
        {
            if (!this.Request.GetQueryNameValuePairs().Any(kv => kv.Key.Equals("access_token")) &&
                (this.Request.Headers.Authorization == null || !this.Request.Headers.Authorization.Scheme.Equals("Bearer", StringComparison.OrdinalIgnoreCase)))
            {
                applicationUser = null;
                membershipUser = null;
                return false;
            }

            IList<HttpApplicationInterface> apis = ComponentRegistry.Resolve<HttpApplicationInterfaceService>().FindByPrivilegeNotNull();
            //将api装载到HttpApplicationInterfaceRouteCollection
            HttpApplicationInterfaceRouteCollection httpApiRouteCollection = new HttpApplicationInterfaceRouteCollection(apis);
            IList<HttpApplicationInterface> matchedApis = httpApiRouteCollection.GetApplicationInterfaces(this.Request);

            //与当前URL进行匹配，获取url相关的privilege       
            List<Privilege> priviles = new List<Privilege>();
            foreach (var api in matchedApis)
            {
                priviles.AddRange(api.Privileges);
            }
            priviles = priviles.Distinct().ToList();

            IList<string> requiredScopes = new List<string>();
            foreach (var privilege in priviles)
            {
                requiredScopes.Add(privilege.ToString());
            }


            var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(
                                            CreateAuthorizationServerSigningServiceProvider(),
                                            CreateResourceServerEncryptionServiceProvider()));
            var accessToken = resourceServer.GetAccessToken(this.Request, requiredScopes.ToArray());
            WebApplicationCredential webApplicationCredential =
                       ComponentRegistry.Resolve<IWebApplicationCredentialService>().FindByClientId(accessToken.ClientIdentifier??this.GetParameterValue("client_id").ToString());

            ApplicationIdentifier = webApplicationCredential.ClientId;

            applicationUser = webApplicationCredential.ApplicationUser;
            membershipUser = ComponentRegistry.Resolve<IMembershipUserService>().FindByClaimedIdentifier(accessToken.User);
            _membershipUser = membershipUser;

            return true;
        }
        private static readonly RSACryptoServiceProvider AuthorizationServerSigningPublicKey = (RSACryptoServiceProvider)OAuthX509Certificates.Instance.SigningCertificate.PublicKey.Key;
        private static readonly RSACryptoServiceProvider ResourceServerEncryptionPrivateKey = (RSACryptoServiceProvider)OAuthX509Certificates.Instance.EncryptionCertificate.PrivateKey;
        public string ApplicationIdentifier { get; private set; }
        private static RSACryptoServiceProvider CreateAuthorizationServerSigningServiceProvider()
        {
            var authorizationServerSigningServiceProvider = AuthorizationServerSigningPublicKey;
            return authorizationServerSigningServiceProvider;
        }
        private static RSACryptoServiceProvider CreateResourceServerEncryptionServiceProvider()
        {
            var resourceServerEncryptionServiceProvider = ResourceServerEncryptionPrivateKey;
            return resourceServerEncryptionServiceProvider;
        }
        private bool AuthorizePublicApi(out IApplicationUser applicationUser, out IMembershipUser membershipUser)
        {
            object appKey = null;
            if (base.TryGetParameterValue("key", out appKey))
            {
                ApplicationIdentifier = appKey as string;
                PublicApiAccessCredentialService publicApiAccessCredentialService = ComponentRegistry.Resolve<PublicApiAccessCredentialService>();
                applicationUser = publicApiAccessCredentialService.FindByApiKey(appKey.ToString()).ApplicationUser;
                //todo: ApplicationUser->Application->Membership->Membershipuser;
               Memberships.Models.Membership membership = (Inovout.Memberships.Models.Membership)(((ApplicationUser)applicationUser).Application.Membership);
                membership  = ComponentRegistry.Resolve<IRepositoryService<Inovout.Memberships.Models.Membership>>().FindById((object)membership.Id);
                membershipUser = ComponentRegistry.Resolve<MembershipUserService>().FindByMembership(membership);
                _membershipUser = membershipUser;
                //membershipUser = ComponentRegistry.Resolve<IMembershipUserService>().FindByClaimedIdentifier(accessToken.User);
                return GetDataOwner().Equals(membershipUser.Membership);
            }
            applicationUser = null;
            membershipUser = null;
            return false;

        }
      

        protected virtual Inovout.Memberships.Models.Membership GetDataOwner()
        {
            if (Project == null) 
            {
                return null;
            }
            return (Inovout.Memberships.Models.Membership)(Project.Membership);        
        }

        protected override void OnAuthorization()
        {
            IApplicationUser applicationUser = null;
            IMembershipUser membershipUser = null;
            if (AuthorizeAccessControl(out applicationUser, out membershipUser) ||
                AuthorizeOAuth(out applicationUser, out membershipUser) ||
                AuthorizePublicApi(out applicationUser, out membershipUser))
            {
                OnAuthorizationAs(new ApplicationUserPrincipal(applicationUser, membershipUser));
            }
            //else
            //{
            //    OnAuthorizationAs(new ApplicationUserPrincipal(applicationUser));
            //}
        }

        protected virtual HttpResponseMessage Content(string content)
        {
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
            response.Content = new StringContent(content);
            return response;
        }

        //protected override void Initialize()
        //{
        //    if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
        //    {
        //        MembershipUser = ComponentRegistry.Resolve<IMembershipUserService>().FindByClaimedIdentifier(Thread.CurrentPrincipal.Identity.Name);
        //    }

        //}
    }
}